﻿/*******************************************************
Copyright © 2007-2009 Active Technologies Group, Inc. (ATGi)

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*******************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommunityServer.Components;
using Newtonsoft.Json;

namespace ATGi.CS.BrightCove
{
    public static class BrightCoveVideos
    {
        public static BrightCoveResultSet<BrightCoveVideo> FindAllVideos(int pageSize, int pageNumber,
            BCSortByType sortBy, BCSortOrder sortOrder, List<String> fields)
        {
            string key = CreateQueryKey(pageSize, pageNumber, "find_all_videos", null, sortBy, sortOrder);
            BrightCoveResultSet<BrightCoveVideo> result = CSCache.Get(key) as BrightCoveResultSet<BrightCoveVideo>;
            if (result == null)
            {
                BrightCoveRequest req = new BrightCoveRequest();
                Dictionary<String, String> reqparams = new Dictionary<string, string>();

                //Build the REST parameter list
                reqparams.Add("command", "find_all_videos");
                reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
                reqparams.Add("get_item_count", Boolean.TrueString);
                if (fields != null) reqparams.Add("fields", Implode(fields));
                reqparams.Add("sort_order", sortOrder.ToString());
                reqparams.Add("sort_by", sortBy.ToString());
                if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
                if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

                //Get the JSon reader returned from the APIRequest
                JsonReader reader = req.Execute(reqparams);
                //Return a list of videos
                result = GetMultipleVideos(reader);
                CSCache.Insert(key, result, BrightCoveConfiguration.Instance.CacheLength);
            }
            return result;
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByUserId(String userId, int pageSize,
             int pageNumber, BCSortByType sortBy, BCSortOrder sortOrder,
             List<String> fields)
        {
            string key = CreateQueryKey(pageSize, pageNumber, "find_videos_by_user_id", userId, sortBy, sortOrder);
            BrightCoveResultSet<BrightCoveVideo> result = CSCache.Get(key) as BrightCoveResultSet<BrightCoveVideo>;
            if (result == null)
            {
                BrightCoveRequest req = new BrightCoveRequest();
                Dictionary<String, String> reqparams = new Dictionary<string, string>();

                //Build the REST parameter list
                reqparams.Add("command", "find_videos_by_user_id");
                reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
                reqparams.Add("user_id", userId);
                reqparams.Add("get_item_count", Boolean.TrueString);
                if (fields != null) reqparams.Add("fields", Implode(fields));
                reqparams.Add("sort_order", sortOrder.ToString());
                reqparams.Add("sort_by", sortBy.ToString());
                if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
                if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

                //Get the JSon reader returned from the APIRequest
                JsonReader reader = req.Execute(reqparams);

                //Return a list of videos
                result = GetMultipleVideos(reader);
                CSCache.Insert(key, result, BrightCoveConfiguration.Instance.CacheLength);
            }
            return result;
        }


        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByCampaignId(long campaignId, int pageSize,
             int pageNumber, BCSortByType sortBy, BCSortOrder sortOrder,
             List<String> fields)
        {
            string key = CreateQueryKey(pageSize, pageNumber, "find_videos_by_campaign_id", campaignId, sortBy, sortOrder);
            BrightCoveResultSet<BrightCoveVideo> result = CSCache.Get(key) as BrightCoveResultSet<BrightCoveVideo>;
            if (result == null)
            {
                BrightCoveRequest req = new BrightCoveRequest();
                Dictionary<String, String> reqparams = new Dictionary<string, string>();

                //Build the REST parameter list
                reqparams.Add("command", "find_videos_by_campaign_id");
                reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
                reqparams.Add("campaign_id", campaignId.ToString());
                reqparams.Add("get_item_count", Boolean.TrueString);
                if (fields != null) reqparams.Add("fields", Implode(fields));
                reqparams.Add("sort_order", sortOrder.ToString());
                reqparams.Add("sort_by", sortBy.ToString());
                if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
                if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

                //Get the JSon reader returned from the APIRequest
                JsonReader reader = req.Execute(reqparams);

                //Return a list of videos
                result = GetMultipleVideos(reader);
                CSCache.Insert(key, result, BrightCoveConfiguration.Instance.CacheLength);
            }
            return result;
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByText(String text, int pageSize,
            int pageNumber, BCSortByType sortBy, BCSortOrder sortOrder,
            List<String> fields)
        {
            string key = CreateQueryKey(pageSize, pageNumber, "find_videos_by_text", text, sortBy, sortOrder);
            BrightCoveResultSet<BrightCoveVideo> result = CSCache.Get(key) as BrightCoveResultSet<BrightCoveVideo>;
            if (result == null)
            {
                BrightCoveRequest req = new BrightCoveRequest();
                Dictionary<String, String> reqparams = new Dictionary<string, string>();

                //Build the REST parameter list
                reqparams.Add("command", "find_videos_by_text");
                reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
                reqparams.Add("text", text);
                reqparams.Add("get_item_count", Boolean.TrueString);
                if (fields != null) reqparams.Add("fields", Implode(fields));
                reqparams.Add("sort_order", sortOrder.ToString());
                reqparams.Add("sort_by", sortBy.ToString());
                if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
                if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

                //Get the JSon reader returned from the APIRequest
                JsonReader reader = req.Execute(reqparams);

                //Return a list of videos
                result = GetMultipleVideos(reader);
                CSCache.Insert(key, result, BrightCoveConfiguration.Instance.CacheLength);
            }
            return result;
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByTags(String and_tags, String or_tags)
        {
            return FindVideosByTags(and_tags, or_tags, -1, -1, BCSortByType.CREATION_DATE,
                 BCSortOrder.ASC, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByTags(String and_tags, String or_tags,
             int pageSize, int pageNumber)
        {
            return FindVideosByTags(and_tags, or_tags, pageSize, pageNumber,
                   BCSortByType.CREATION_DATE, BCSortOrder.ASC, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByTags(String and_tags, String or_tags,
             int pageSize, int pageNumber, BCSortByType sortBy, BCSortOrder sortOrder)
        {
            return FindVideosByTags(and_tags, or_tags, pageSize, pageNumber, sortBy, sortOrder, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByTags(String and_tags, String or_tags,
             int pageSize, int pageNumber, BCSortByType sortBy, BCSortOrder sortOrder,
             List<String> fields)
        {
            BrightCoveRequest req = new BrightCoveRequest();
            Dictionary<String, String> reqparams = new Dictionary<string, string>();

            //Build the REST parameter list
            reqparams.Add("command", "find_videos_by_tags");
            reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
            reqparams.Add("and_tags", and_tags);
            reqparams.Add("or_tags", or_tags);
            reqparams.Add("get_item_count",Boolean.TrueString);
            if (fields != null) reqparams.Add("fields", Implode(fields));
            reqparams.Add("sort_order", sortOrder.ToString());
            reqparams.Add("sort_by", sortBy.ToString());
            if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
            if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

            //Get the JSon reader returned from the APIRequest
            JsonReader reader = req.Execute(reqparams);

            //Return a list of videos
            return GetMultipleVideos(reader);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindRelatedVideos(long videoId)
        {
            return FindRelatedVideos(videoId, -1, -1, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindRelatedVideos(long videoId, int pageSize, int pageNumber)
        {
            return FindRelatedVideos(videoId, pageSize, pageNumber, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindRelatedVideos(long videoId, int pageSize,
                int pageNumber, List<String> fields)
        {
            string key = CreateQueryKey(pageSize, pageNumber, "find_related_videos", videoId, BCSortByType.CREATION_DATE, BCSortOrder.ASC);
            BrightCoveResultSet<BrightCoveVideo> result = CSCache.Get(key) as BrightCoveResultSet<BrightCoveVideo>;
            if (result == null)
            {
                BrightCoveRequest req = new BrightCoveRequest();
                Dictionary<String, String> reqparams = new Dictionary<string, string>();

                //Build the REST parameter list
                reqparams.Add("command", "find_related_videos");
                reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
                reqparams.Add("video_id", videoId.ToString());
                reqparams.Add("get_item_count", Boolean.TrueString);
                if (fields != null) reqparams.Add("fields", Implode(fields));
                if (pageNumber >= 0) reqparams.Add("page_number", pageNumber.ToString());
                if (pageSize >= 0) reqparams.Add("page_size", pageSize.ToString());

                //Get the JSon reader returned from the APIRequest
                JsonReader reader = req.Execute(reqparams);
                //Return a list of videos
                result = GetMultipleVideos(reader);
                CSCache.Insert(key, result, BrightCoveConfiguration.Instance.CacheLength);
            }
            return result;
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByIds(List<long> videoIds)
        {
            return FindVideosByIds(videoIds, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByIds(List<long> videoIds,
               List<String> fields)
        {
            BrightCoveRequest req = new BrightCoveRequest();
            Dictionary<String, String> reqparams = new Dictionary<string, string>();

            //Build the REST parameter list
            reqparams.Add("command", "find_videos_by_ids");
            reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
            reqparams.Add("video_ids", Implode(videoIds));
            if (fields != null) reqparams.Add("fields", Implode(fields));

            //Get the JSon reader returned from the APIRequest
            JsonReader reader = req.Execute(reqparams);

            //Return a list of videos

            return GetMultipleVideos(reader);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByReferenceIds(List<String> referenceIds)
        {
            return FindVideosByReferenceIds(referenceIds, null);
        }

        public static BrightCoveResultSet<BrightCoveVideo> FindVideosByReferenceIds(List<String>
                referenceIds, List<String> fields)
        {
            BrightCoveRequest req = new BrightCoveRequest();
            Dictionary<String, String> reqparams = new Dictionary<string, string>();

            //Build the REST parameter list
            reqparams.Add("command", "find_videos_by_reference_ids");
            reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
            reqparams.Add("reference_ids", Implode(referenceIds));
            if (fields != null) reqparams.Add("fields", Implode(fields));

            //Get the JSon reader returned from the APIRequest
            JsonReader reader = req.Execute(reqparams);

            //Return a list of videos

            return GetMultipleVideos(reader);
        }

        public static BrightCoveVideo FindVideoById(long videoId)
        {
            return FindVideoById(videoId, null);
        }

        public static BrightCoveVideo FindVideoById(long videoId, List<String> fields)
        {
            BrightCoveRequest req = new BrightCoveRequest();
            Dictionary<String, String> reqparams = new Dictionary<string, string>();

            //Build the REST parameter list
            reqparams.Add("command", "find_video_by_id");
            reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
            reqparams.Add("video_id", videoId.ToString());
            if (fields != null) reqparams.Add("fields", Implode(fields));

            //Get the JSon reader returned from the APIRequest
            JsonReader reader = req.Execute(reqparams);

            //Return a single video
            return GetSingleVideo(reader);
        }

        public static BrightCoveVideo GetVideoFromUrl(string videoUrl)
        {
            if (!Uri.IsWellFormedUriString(videoUrl, UriKind.Absolute))
                throw new InvalidOperationException("The video url must be a properly formed absolute url to the video");
            if (RegularExpressions.BrightCoveRegex.IsMatch(videoUrl))
            {
                long idResult;
                if (long.TryParse(RegularExpressions.BrightCoveRegex.Match(videoUrl).Groups[RegularExpressions.TitleIdGroup].Value, out idResult))
                    return FindVideoById(idResult);
            }
            return null;
        }

        public static BrightCoveVideo FindVideoByReferenceId(String referenceId)
        {
            return FindVideoByReferenceId(referenceId, null);
        }

        public static BrightCoveVideo FindVideoByReferenceId(String referenceId, List<String> fields)
        {
            BrightCoveRequest req = new BrightCoveRequest();
            Dictionary<String, String> reqparams = new Dictionary<string, string>();

            //Build the REST parameter list
            reqparams.Add("command", "find_video_by_reference_id");
            reqparams.Add("token", BrightCoveConfiguration.Instance.ReadToken);
            reqparams.Add("reference_id", referenceId);
            if (fields != null) reqparams.Add("fields", Implode(fields));

            //Get the JSon reader returned from the APIRequest
            JsonReader reader = req.Execute(reqparams);

            //Return a single video
            return GetSingleVideo(reader);
        }

        private static BrightCoveResultSet<BrightCoveVideo> GetMultipleVideos(JsonReader reader)
        {
            BrightCoveResultSet<BrightCoveVideo> videos = new BrightCoveResultSet<BrightCoveVideo>();
            //Get the first start object
            reader.Read();
            if (reader.TokenType == JsonToken.StartObject)
            {
                //Check if this is an array of videos
                reader.Read();
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    if (reader.Value.ToString() == "items")
                    {
                        reader.Read();
                        if (reader.TokenType == JsonToken.StartArray)
                        {
                            //Parse all video objects within the array
                            reader.Read();
                            while (reader.TokenType == JsonToken.StartObject)
                            {
                                BrightCoveVideo video = new BrightCoveVideo(reader);
                                videos.Items.Add(video);
                            }
                        }
                    }
                    
                    else if (reader.Value.ToString() == "error")
                    {
                        reader.Read();
                        EventLogs.Write(String.Format("Error: {0}", reader.Value), "BrightCove", 80001, EventType.Error);
                    }
                }
                else
                {
                    //Unexpected JSON format within string
                }
            }
            else
            {
                //Unexpected JSON format at beginning of string
            }
            while (reader.Read())
            {
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    if (reader.Value.ToString() == "total_count")
                    {
                        reader.Read();
                        videos.TotalRecords = Int32.Parse(reader.Value.ToString());
                    }
                }
            }
            return videos;
        }

        private static BrightCoveVideo GetSingleVideo(JsonReader reader)
        {
            BrightCoveVideo video = null;
            reader.Read();
            if (reader.TokenType == JsonToken.StartObject)
            {
                video = new BrightCoveVideo(reader);
            }
            else
            {
                EventLogs.Write(String.Format("Error: {0}", reader.Value),"BrightCove",80001,EventType.Error);
                //Error handling
            }
            return video;
        }

        private static String Implode(List<String> values)
        {
            String result = "";
            foreach (String s in values)
            {
                result = result + s + ",";
            }
            return result;
        }

        private static String Implode(List<long> values)
        {
            String result = "";
            foreach (long l in values)
            {
                result = result + l.ToString() + ",";
            }
            return result;
        }

        static readonly string keyFormat = "PS:{0};PI:{1};CMD:{2};ID:{3};ST:{4};SO:{5}";
        private static string CreateQueryKey(int pageSize, int pageIndex, string command, object id, BCSortByType sortType, BCSortOrder sortOrder)
        {
            string key = String.Format(keyFormat, pageSize, pageIndex, command, id, sortType, sortOrder);
            return key;
        }
    }

    public enum BCSortByType
    {
        PUBLISH_DATE, CREATION_DATE, MODIFIED_DATE,
        PLAYS_TOTAL, PLAYS_TRAILING_WEEK
    };

    public enum BCSortOrder
    {
        ASC,
        DESC,
    }
}
